package com.dayu.gulimall.thread;

import java.util.concurrent.*;

/**
 * @author dayu
 * @version 1.0
 * @email dayu007@foxmail.com
 * @date 2021/1/19 21:36
 * @description 多线程
 * 1、继承Thread
 * 异步执行线程
 * System.out.println("====thread start====");
 * new Thread01().start();
 * System.out.println("====thread end====");
 * <p>
 * 2、实现Runnable
 * System.out.println("====thread start====");
 * MyRunnable myRunnable = new MyRunnable();
 * new Thread(myRunnable).start();
 * System.out.println("====thread end====");
 * <p>
 * 3、实现Callable
 * System.out.println("====thread start====");
 * FutureTask<Integer> task = new FutureTask<>(new Callable01());
 * Thread thread = new Thread(task);
 * thread.start();
 * //通过get方法获取线程返回值，此方法阻塞执行，get方法执行后才继续执行下面的代码
 * Integer integer = task.get();
 * System.out.println(integer);
 * System.out.println("====thread end====");
 * <p>
 * 以上三种实现方法都不可用，当有任务进来的时候多线程可能会耗尽资源，这时候需要引用线程池
 * 4、线程池Executors
 * //这个方法也不合适，这里可以指定固定生成的线程数量
 * ExecutorService executorService = Executors.newFixedThreadPool(10);
 * executorService.execute(new Thread01());
 * executorService.execute(new MyRunnable());
 * <p>
 * ThreadPoolExecutor 七大参数
 * 使用给定的初始参数创建一个新的ThreadPoolExecutor 。
 * 参数：
 * corePoolSize –保留在池中的线​​程数，即使它们处于空闲状态，除非设置了allowCoreThreadTimeOut
 * maximumPoolSize –池中允许的最大线程数
 * keepAliveTime –当线程数大于内核数时，这是多余的空闲线程将在终止之前等待新任务的最长时间。
 * unit – keepAliveTime参数的时间单位
 * workQueue –在执行任务之前用于保留任务的队列。 此队列将仅保存execute方法提交的Runnable任务。
 * threadFactory –执行程序创建新线程时要使用的工厂
 * RejectedExecutionHandler handler –因达到线程界限和队列容量而被阻止执行时使用的处理程序
 * 抛出：
 * IllegalArgumentException如果以下条件之一成立：
 * corePoolSize < 0
 * keepAliveTime < 0
 * maximumPoolSize <= 0
 * maximumPoolSize < corePoolSize
 * NullPointerException如果workQueue或threadFactory或handler为null
 * <p>
 * 工作流程：
 * 1）、线程池创建，准备好core数量的线程，准备接收任务
 * 1.1 、 core核心线程满了，就将再进来的任务放到阻塞队列里面，空闲的core线程就会自己去阻塞队列里面取任务
 * 1.2、 阻塞队列满了，就直接开新线程执行，最大只能开到max指定的数量。
 * 1.3、 max满了就用拒绝策略 RejectedExecutionHandler 拒绝任务。
 * 1.4、 max都执行完了，有很多空闲线程，在指定的时间keepAliveTime以后，释放这些线程
 * 注意：
 * 阻塞队列 new LinkedBlockingDeque<>()的默认大小是 this(Integer.MAX_VALUE)，导致内存不足
 * <p>
 * 案例：
 * 有一个线程池，core7 ,max 20 ,queue: 50,现在有100个并发进来，问：线程是如何分配的？
 * 解析：7个立即执行，50个进入队列queue，另外再开13线程执行（max：20），剩下的30个执行拒绝策略。
 * 拒绝策略通常是丢弃，如果不想丢弃还要执行。CallerRunsPolicy
 */
public class MyThread {

    private static ExecutorService executor = Executors.newFixedThreadPool(10);


    /**
     * 线程串行化
     *
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("====thread start====");

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程1执行了");
            return "hello";
        }, executor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程2执行了");
            return "xiaoming";
        }, executor);

//        future1.runAfterBothAsync(future2,()->{
//            System.out.println("线程3执行了，无返回");
//        },executor);

        //可以接收以上线程结果，并返回自己的结果
        CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (s, s2) -> {
            return s + " ：" + s2 + "--->你好！";
        }, executor);

        //future.get();是个阻塞线程，只有等待线程执行结束才继续后面的代码
        System.out.println("====thread end====" + future3.get());
    }


    /**
     * 线程串行化
     *
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void CompletableFuture01(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("====thread start====");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 3;
            System.out.println("线程1执行结束了。。。" + i);
            return i;
        }, executor).thenApplyAsync(res -> {
            System.out.println("执行线程2");
            System.out.println("接收到上一个线程结果：" + res);
            return "hello name " + res * 2;
        }, executor);

        //future.get();是个阻塞线程，只有等待线程执行结束才继续后面的代码
        System.out.println("====thread end====" + future.get());
    }

    public static void executor() throws ExecutionException, InterruptedException {
        System.out.println("====thread start====");

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,
                200,
                20,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10000),//默认integer的最大值，这里一定要设置最大队列的容量
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        Executors.newFixedThreadPool(10);
        Executors.newCachedThreadPool();
        Executors.newSingleThreadExecutor();
        Executors.newScheduledThreadPool(10, Executors.defaultThreadFactory());
        Executors.newScheduledThreadPool(10);
//        ExecutorService executorService=Executors.newScheduledThreadPool();

        System.out.println("====thread end====");
    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            int a = 10 / 5;
            System.out.println("------a==------" + a);
        }
    }

    public static class MyRunnable implements Runnable {
        @Override
        public void run() {
            int a = 10 / 5;
            System.out.println("------a==------" + a);
        }
    }

    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() {
            int a = 10 / 5;
            System.out.println("------a==------" + a);
            return a;
        }
    }


}
